#include "GridLayer.h"
#include <math.h>
#include <GL/glew.h>

GridLayer::GridLayer(int res_m, int res_n, int res_l, int l, int numTilesX, int numTilesY, int rownum, int columnum)
{
	this->res_m = res_m;
	this->res_n = res_n;
	this->res_l = res_l;
	this->l = l;

	int M = res_m + 2; //2 pixel bound edges
	int N = res_n + 2; //2 pixel bound edges
	int L = res_l + 2; //2 bound layers

	if(res_l == 1) L = 1;

	rowNum = rownum;
	columnNum = columnum;

	float tileSizeX = 1.f / (float) numTilesX;
	float tileSizeY = 1.f / (float) numTilesY;
	float pixelSizeX = tileSizeX / (float) M;
	float pixelSizeY = tileSizeY / (float) N;

	MinPos[0] = columnNum * tileSizeX + pixelSizeX;
	MinPos[0] = MinPos[0] * 2.f - 1.f;
	MinPos[1] = rowNum * tileSizeY + pixelSizeY;
	MinPos[1] = MinPos[1] * 2.f - 1.f;
	MaxPos[0] = (columnNum + 1) * tileSizeX - pixelSizeX;
	MaxPos[0] = MaxPos[0] * 2.f - 1.f;
	MaxPos[1] = (rowNum + 1) * tileSizeY - pixelSizeY;
	MaxPos[1] = MaxPos[1] * 2.f - 1.f;
	//vertex positions
	quadVertices[0].pos[0] = MinPos[0];
	quadVertices[0].pos[1] = MinPos[1];
	quadVertices[1].pos[0] = MaxPos[0];
	quadVertices[1].pos[1] = MinPos[1];
	quadVertices[2].pos[0] = MaxPos[0];
	quadVertices[2].pos[1] = MaxPos[1];
	quadVertices[3].pos[0] = MinPos[0];
	quadVertices[3].pos[1] = MaxPos[1];
	//vertex coordinates
	MinCoord[0] = columnNum * M + 1;
	MinCoord[1] = rowNum * N + 1;
	MaxCoord[0] = (columnNum + 1) * M - 1;
	MaxCoord[1] = (rowNum + 1) * N - 1;
	quadVertices[0].coord[0] = MinCoord[0];
	quadVertices[0].coord[1] = MinCoord[1];
	quadVertices[0].coord[2] = 0;
	quadVertices[0].coord[3] = 0;
	quadVertices[1].coord[0] = MaxCoord[0];
	quadVertices[1].coord[1] = MinCoord[1];
	quadVertices[1].coord[2] = res_m;
	quadVertices[1].coord[3] = 0;
	quadVertices[2].coord[0] = MaxCoord[0];
	quadVertices[2].coord[1] = MaxCoord[1];
	quadVertices[2].coord[2] = res_m;
	quadVertices[2].coord[3] = res_n;
	quadVertices[3].coord[0] = MinCoord[0];
	quadVertices[3].coord[1] = MaxCoord[1];
	quadVertices[3].coord[2] = 0;
	quadVertices[3].coord[3] = res_n;
	//offsets to upper and lower layers
	UpperLayerOffset[0] = M;
	UpperLayerOffset[1] = 0;
	LowerLayerOffset[0] = -M;
	LowerLayerOffset[1] = 0;
	quadVertices[0].offsetCoords[0] = quadVertices[0].coord[0] + UpperLayerOffset[0];
	quadVertices[0].offsetCoords[2] = quadVertices[0].coord[0] + LowerLayerOffset[0];
	if(quadVertices[0].offsetCoords[0] > M * numTilesX)
	{UpperLayerOffset[0] -= numTilesX * M; UpperLayerOffset[1] = N;}
	if(quadVertices[0].offsetCoords[2] < 0)
	{LowerLayerOffset[0] += numTilesX * M; LowerLayerOffset[1] = -N;}
	quadVertices[0].offsetCoords[0] = quadVertices[0].coord[0] + UpperLayerOffset[0];
	quadVertices[0].offsetCoords[1] = quadVertices[0].coord[1] + UpperLayerOffset[1];
	quadVertices[0].offsetCoords[2] = quadVertices[0].coord[0] + LowerLayerOffset[0];
	quadVertices[0].offsetCoords[3] = quadVertices[0].coord[1] + LowerLayerOffset[1];
	quadVertices[1].offsetCoords[0] = quadVertices[1].coord[0] + UpperLayerOffset[0];
	quadVertices[1].offsetCoords[1] = quadVertices[1].coord[1] + UpperLayerOffset[1];
	quadVertices[1].offsetCoords[2] = quadVertices[1].coord[0] + LowerLayerOffset[0];
	quadVertices[1].offsetCoords[3] = quadVertices[1].coord[1] + LowerLayerOffset[1];
	quadVertices[2].offsetCoords[0] = quadVertices[2].coord[0] + UpperLayerOffset[0];
	quadVertices[2].offsetCoords[1] = quadVertices[2].coord[1] + UpperLayerOffset[1];
	quadVertices[2].offsetCoords[2] = quadVertices[2].coord[0] + LowerLayerOffset[0];
	quadVertices[2].offsetCoords[3] = quadVertices[2].coord[1] + LowerLayerOffset[1];
	quadVertices[3].offsetCoords[0] = quadVertices[3].coord[0] + UpperLayerOffset[0];
	quadVertices[3].offsetCoords[1] = quadVertices[3].coord[1] + UpperLayerOffset[1];
	quadVertices[3].offsetCoords[2] = quadVertices[3].coord[0] + LowerLayerOffset[0];
	quadVertices[3].offsetCoords[3] = quadVertices[3].coord[1] + LowerLayerOffset[1];

	///fill bound edge information	
	boundEdges[0].normal[0] = 0;
	boundEdges[0].normal[1] = 1;
	boundEdges[0].pos1[0] = quadVertices[0].pos[0] + pixelSizeX;
	boundEdges[0].pos1[1] = quadVertices[0].pos[1] - pixelSizeY;
	boundEdges[0].pos2[0] = quadVertices[1].pos[0] - pixelSizeX;
	boundEdges[0].pos2[1] = quadVertices[1].pos[1] - pixelSizeY;
	boundEdges[0].coord1[0] = quadVertices[0].coord[0] - 1;
	boundEdges[0].coord1[1] = quadVertices[0].coord[1] - 1;
	boundEdges[0].coord2[0] = quadVertices[1].coord[0] - 1;
	boundEdges[0].coord2[1] = quadVertices[1].coord[1] - 1;

	boundEdges[1].normal[0] = -1;
	boundEdges[1].normal[1] = 0;
	boundEdges[1].pos1[0] = quadVertices[1].pos[0] + pixelSizeX;
	boundEdges[1].pos1[1] = quadVertices[1].pos[1] + pixelSizeY;
	boundEdges[1].pos2[0] = quadVertices[2].pos[0] + pixelSizeX;
	boundEdges[1].pos2[1] = quadVertices[2].pos[1] - pixelSizeY;
	boundEdges[1].coord1[0] = quadVertices[1].coord[0] + 1;
	boundEdges[1].coord1[1] = quadVertices[1].coord[1] - 1;
	boundEdges[1].coord2[0] = quadVertices[2].coord[0] + 1;
	boundEdges[1].coord2[1] = quadVertices[2].coord[1] - 1;

	boundEdges[2].normal[0] = 0;
	boundEdges[2].normal[1] = -1;
	boundEdges[2].pos1[0] = quadVertices[3].pos[0] + pixelSizeX;
	boundEdges[2].pos1[1] = quadVertices[3].pos[1] + pixelSizeY;
	boundEdges[2].pos2[0] = quadVertices[2].pos[0] - pixelSizeX;
	boundEdges[2].pos2[1] = quadVertices[2].pos[1] + pixelSizeY;
	boundEdges[2].coord1[0] = quadVertices[3].coord[0] + 1;
	boundEdges[2].coord1[1] = quadVertices[3].coord[1] + 1;
	boundEdges[2].coord2[0] = quadVertices[2].coord[0] + 1;
	boundEdges[2].coord2[1] = quadVertices[2].coord[1] + 1;

	boundEdges[3].normal[0] = 1;
	boundEdges[3].normal[1] = 0;
	boundEdges[3].pos1[0] = quadVertices[0].pos[0] - pixelSizeX;
	boundEdges[3].pos1[1] = quadVertices[0].pos[1] + pixelSizeY;
	boundEdges[3].pos2[0] = quadVertices[3].pos[0] - pixelSizeX;
	boundEdges[3].pos2[1] = quadVertices[3].pos[1] - pixelSizeY;
	boundEdges[3].coord1[0] = quadVertices[0].coord[0] - 1;
	boundEdges[3].coord1[1] = quadVertices[0].coord[1] + 1;
	boundEdges[3].coord2[0] = quadVertices[3].coord[0] - 1;
	boundEdges[3].coord2[1] = quadVertices[3].coord[1] + 1;
}

GridLayer::~GridLayer(void)
{

}

void GridLayer::DrawQuad(float z)
{
	glBegin(GL_QUADS);
	for (int i = 0; i < 4; i++)
	{
		glMultiTexCoord4fv(GL_TEXTURE0_ARB, quadVertices[i].coord);
		glMultiTexCoord4fv(GL_TEXTURE1_ARB, quadVertices[i].offsetCoords);

		glVertex3f(quadVertices[i].pos[0], quadVertices[i].pos[1], z);
	}
	glEnd();
}

void GridLayer::DrawBounds(float z)
{
	glBegin(GL_LINES);
	for(int i = 0; i < 4; i++)
	{
		float coords[4];
		coords[0] = boundEdges[i].coord1[0];
		coords[1] = boundEdges[i].coord1[1];
		coords[2] = boundEdges[i].normal[0];
		coords[3] = boundEdges[i].normal[1];
		glTexCoord4fv(coords);
		glVertex3f(boundEdges[i].pos1[0], boundEdges[i].pos1[1], z);
		coords[0] = boundEdges[i].coord2[0];
		coords[1] = boundEdges[i].coord2[1];
		glTexCoord4fv(coords);
		glVertex3f(boundEdges[i].pos2[0], boundEdges[i].pos2[1], z);
	}
	glEnd();
}

BoundaryLayer::BoundaryLayer(int res_m, int res_n, int res_l, bool up, int numTilesX, int numTilesY)
{
	this->res_m = res_m;
	this->res_n = res_n;
	this->res_l = res_l;
	this->up = up;

	int M = res_m + 2; //2 pixel bound edges
	int N = res_n + 2; //2 pixel bound edges
	int L = res_l + 2; //2 bound layers

	if(res_l == 1) L = 1;

	if(!up)
	{
		columnNum = rowNum = 0;
	}
	else
	{
		int l = res_l + 2;
		rowNum = ceil( (float)(l) / (float)numTilesX); // 1 -> tilesY
		columnNum = l - numTilesX * (rowNum - 1); // 1 -> tilesX
		rowNum -= 1; // 0 -> tilesY-1
		columnNum -= 1; // 0 -> tilesX-1
	}

	float tileSizeX = 1.f / (float) numTilesX;
	float tileSizeY = 1.f / (float) numTilesY;
	float pixelSizeX = tileSizeX / (float) M;
	float pixelSizeY = tileSizeY / (float) N;

	MinPos[0] = columnNum * tileSizeX + pixelSizeX;
	MinPos[0] = MinPos[0] * 2.f - 1.f;
	MinPos[1] = rowNum * tileSizeY + pixelSizeY;
	MinPos[1] = MinPos[1] * 2.f - 1.f;
	MaxPos[0] = (columnNum + 1) * tileSizeX - pixelSizeX;
	MaxPos[0] = MaxPos[0] * 2.f - 1.f;
	MaxPos[1] = (rowNum + 1) * tileSizeY - pixelSizeY;
	MaxPos[1] = MaxPos[1] * 2.f - 1.f;
	//vertex positions
	quadVertices[0].pos[0] = MinPos[0];
	quadVertices[0].pos[1] = MinPos[1];
	quadVertices[1].pos[0] = MaxPos[0];
	quadVertices[1].pos[1] = MinPos[1];
	quadVertices[2].pos[0] = MaxPos[0];
	quadVertices[2].pos[1] = MaxPos[1];
	quadVertices[3].pos[0] = MinPos[0];
	quadVertices[3].pos[1] = MaxPos[1];
	//vertex coordinates
	MinCoord[0] = columnNum * M + 1;
	MinCoord[1] = rowNum * N + 1;
	MaxCoord[0] = (columnNum + 1) * M - 1;
	MaxCoord[1] = (rowNum + 1) * N - 1;
	quadVertices[0].coord[0] = MinCoord[0];
	quadVertices[0].coord[1] = MinCoord[1];
	quadVertices[1].coord[0] = MaxCoord[0];
	quadVertices[1].coord[1] = MinCoord[1];
	quadVertices[2].coord[0] = MaxCoord[0];
	quadVertices[2].coord[1] = MaxCoord[1];
	quadVertices[3].coord[0] = MinCoord[0];
	quadVertices[3].coord[1] = MaxCoord[1];
	//offsets to upper and lower layers
	NextLayerOffset[0] = M;
	if(up)
		NextLayerOffset[0] *= -1;
	NextLayerOffset[1] = 0;
	quadVertices[0].offsetCoords[0] = quadVertices[0].coord[0] + NextLayerOffset[0];
	if(quadVertices[0].offsetCoords[0] > M * numTilesX)
	{NextLayerOffset[0] -= numTilesX * M; NextLayerOffset[1] = N;}
	if(quadVertices[0].offsetCoords[0] < 0)
	{NextLayerOffset[0] += numTilesX * M; NextLayerOffset[1] = -N;}
	quadVertices[0].offsetCoords[0] = quadVertices[0].coord[0] + NextLayerOffset[0];
	quadVertices[0].offsetCoords[1] = quadVertices[0].coord[1] + NextLayerOffset[1];
	quadVertices[1].offsetCoords[0] = quadVertices[1].coord[0] + NextLayerOffset[0];
	quadVertices[1].offsetCoords[1] = quadVertices[1].coord[1] + NextLayerOffset[1];
	quadVertices[2].offsetCoords[0] = quadVertices[2].coord[0] + NextLayerOffset[0];
	quadVertices[2].offsetCoords[1] = quadVertices[2].coord[1] + NextLayerOffset[1];
	quadVertices[3].offsetCoords[0] = quadVertices[3].coord[0] + NextLayerOffset[0];
	quadVertices[3].offsetCoords[1] = quadVertices[3].coord[1] + NextLayerOffset[1];
}

void BoundaryLayer::DrawQuad(float z)
{
	glBegin(GL_QUADS);
	for(int i = 0; i< 4; i++)
	{
		float coords[4];
		coords[0] = quadVertices[i].coord[0];
		coords[1] = quadVertices[i].coord[1];
		coords[2] = quadVertices[i].offsetCoords[0];
		coords[3] = quadVertices[i].offsetCoords[1];
		glTexCoord4fv(coords);
		glVertex4f(quadVertices[i].pos[0],quadVertices[i].pos[1],z,1);
	}	
	glEnd();
}